﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Microsoft.Practices.Unity;
using Vit.Common.Extensions;
using Vit.Web;
using Vit.Web.Models;
using Vit.Mvc.Fakes;
using Vit.Mvc.DataAnnotations;
using Vit.Mvc.Providers;

namespace Vit.Mvc.Extensions
{
    public static class HtmlHelperExtensions
    {
        public static void RenderModules(this HtmlHelper html, string module)
        {
            IPage pageInfo = html.ViewData.Model as IPage;
            if (pageInfo != null)
            {
                var modules = pageInfo.PageModules.Where(o => string.Equals(o.Layout, module, StringComparison.OrdinalIgnoreCase)).OrderBy(o => o.ShowOrder);
                foreach (var part in modules)
                {
                    string url;
                    switch (pageInfo.Mode)
                    {
                        case EditMode.View:
                        default:
                            url = part.Module.ViewUrl;
                            break;
                        case EditMode.Edit:
                            url = part.Module.EditUrl;
                            break;
                        case EditMode.Design:
                            url = part.Module.DesignUrl;
                            break;
                    }

                    var context = new FakeHttpContext("~" + url);
                    var routes = RouteTable.Routes.GetRouteData(context);
                    if (routes.DataTokens["area"] != null)
                        routes.Values.Add("area", routes.DataTokens["area"]);

                    RenderContainer(html, part.Container, routes);
                }
            }
        }

        public static void RenderContainer(this HtmlHelper html, string container, RouteData routes)
        {
            var theme = WebUnity.Current.PortalService.Run(p => p.GetCurrentTheme(), o => o != null);
            container = string.Format("{0}/Containers/{1}", theme.Name, container);
            html.RenderPartial(container, routes, null);
        }

        public static MvcHtmlString SearchFor(this HtmlHelper html, ViewModelMetadata prop, object val, string controlAttributes, string controlStyles)
        {
            string format = prop.EditFormatString;
            if (string.IsNullOrEmpty(format))
                format = "{0}"; 
            foreach (var provider in HtmlRenderProviders)
            {
                var mvcHtml = provider.Render(prop.PropertyName, prop.Search.ControlType, prop.Search.IsRange, format, val, controlAttributes, controlStyles);
                if (!MvcHtmlString.IsNullOrEmpty(mvcHtml))
                {
                    return mvcHtml;
                }
            }
            return null;
        }

        public static MvcHtmlString ListFor(this HtmlHelper html, ViewModelMetadata prop, object val, string controlAttributes, string controlStyles)
        {
          string format = prop.DisplayFormatString;
            if (string.IsNullOrEmpty(format))
                format = "{0}";

            val = GetDisplayInShort(prop, val);

            foreach (var provider in HtmlRenderProviders)
            {
                var mvcHtml = provider.Render(prop.PropertyName, prop.List.ControlType, false, format, val, controlAttributes, controlStyles);
                if (!MvcHtmlString.IsNullOrEmpty(mvcHtml))
                {
                    return mvcHtml;
                }
            }
            return null;
        }

        public static MvcHtmlString DetailFor(this HtmlHelper html, ViewModelMetadata prop, object val, string controlAttributes, string controlStyles)
        {
            string format = prop.DisplayFormatString;
            if (string.IsNullOrEmpty(format))
                format = "{0}";

            val = GetDisplayInShort(prop, val);
            
            foreach (var provider in HtmlRenderProviders)
            {
                var mvcHtml = provider.Render(prop.PropertyName, prop.Detail.ControlType, false, format, val, controlAttributes, controlStyles);
                if (!MvcHtmlString.IsNullOrEmpty(mvcHtml))
                {
                    return mvcHtml;
                }
            }
            return null;
        }

        public static MvcHtmlString EditFor(this HtmlHelper html, ViewModelMetadata prop, object val, string controlAttributes, string controlStyles)
        {
            string format = prop.EditFormatString;
            if (string.IsNullOrEmpty(format))
                format = "{0}";
            foreach (var provider in HtmlRenderProviders)
            {
                var mvcHtml = provider.Render(prop.PropertyName, prop.Edit.ControlType, false, format, val, controlAttributes, controlStyles);
                if (!MvcHtmlString.IsNullOrEmpty(mvcHtml))
                {
                    return mvcHtml;
                }
            }
            return null;
        }

        public static object GetDisplayInShort(ViewModelMetadata prop, object val)
        {
            object shortVal = val;
            if (prop.IsComplexType)
            {
                ViewModelMetadata meta = ModelMetadataProviders.Current.GetMetadataForType(() => val, val.GetType()) as ViewModelMetadata;
                if (meta != null)
                {
                    DisplayInShortAttribute disa = meta.Attributes.FirstOrDefault(o => o is DisplayInShortAttribute) as DisplayInShortAttribute;
                    if (disa != null)
                    {
                        List<object> vals = new List<object>();
                        foreach (var p in disa.Properties)
                            vals.Add(val.GetPropertyValue(p));

                        shortVal = string.Format(disa.Format, vals.ToArray());
                    }
                }
            }
            return shortVal;
        }

        private static IEnumerable<IHtmlRenderProvider> HtmlRenderProviders
        {
            get
            {
                return WebUnity.Current.UnityContainer.ResolveAll<IHtmlRenderProvider>();
            }
        }
    }
}
